home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
gnu
/
elib-006.lha
/
elib-0.06
/
library
/
bintree.el
< prev
next >
Wrap
Lisp/Scheme
|
1993-01-24
|
10KB
|
344 lines
;;;; $Id: bintree.el,v 0.5 1992/08/19 01:57:32 ceder Exp $
;;;; This file implements binary trees.
;;;;
;;;; Copyright (C) 1991, 1992 Free Software Foundation
;;;;
;;;; This file is part of the GNU Emacs lisp library, Elib.
;;;;
;;;; GNU Elib is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation; either version 1, or (at your option)
;;;; any later version.
;;;;
;;;; GNU Elib is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with GNU Emacs; see the file COPYING. If not, write to
;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;;;
;;;; Author: Inge Wallin
;;;;
;;;
;;; A binary tree consists of two cons cells, the first one holding
;;; the tag 'BINTREE in the car cell and the second one having
;;; the tree in the car and the compare function in the cdr cell. The
;;; tree has a dummy node as its root with the real tree in the left
;;; pointer. The compare function must take two arguments of the type
;;; which is to be stored in the tree and must return non-nil if
;;; the first argument is "less than" the second argument and nil
;;; otherwise.
;;;
;;; For example, use
;;; (bintree-create '<)
;;; if the tree is going to store integers.
;;;
;;;
;;; This package uses the macros in the file elib-node.el and
;;; a stack from stack.el.
;;;
(require 'elib-node)
(require 'stack-m)
(provide 'bintree)
;;; ================================================================
;;; Internal functions for use in the binary tree package
(defmacro elib-bintree-root (tree)
;; Return the root node for a binary tree. INTERNAL USE ONLY.
(` (elib-node-left (car (cdr (, tree))))))
(defmacro elib-bintree-dummyroot (tree)
;; Return the dummy node of a binary tree. INTERNAL USE ONLY.
(` (car (cdr (, tree)))))
(defmacro elib-bintree-cmpfun (tree)
;; Return the compare function of binary tree TREE. INTERNAL USE ONLY."
(` (cdr (cdr (, tree)))))
(defun elib-bintree-mapc (map-function root)
;; Apply MAP-FUNCTION to all nodes in the tree starting with ROOT.
;; The function is applied in-order.
;;
;; Note: MAP-FUNCTION is applied to the node and not to the data itself.
;;
;; INTERNAL USE ONLY."
(let ((node root)
(stack (elib-stack-create))
(go-left t))
(elib-stack-push stack nil)
(while node
(if (and go-left
(elib-node-left node))
(progn ; Do the left subtree first.
(elib-stack-push stack node)
(setq node (elib-node-left node)))
(funcall map-function node) ; Apply the function...
(if (elib-node-right node) ; and do the right subtree.
(setq node (elib-node-right node)
go-left t)
(setq node (elib-stack-pop stack)
go-left nil))))))
(defun elib-bintree-do-copy (root)
;; Copy the tree with ROOT as root. Highly recursive. INTERNAL USE ONLY.
(if (null root)
nil
(elib-node-create (elib-bintree-do-copy (elib-node-left root))
(elib-bintree-do-copy (elib-node-right root))
(elib-node-data root))))
;;; ================================================================
;;; The public functions which operate on binary trees.
(defun bintree-create (compare-function)
"Create an empty binary tree using COMPARE-FUNCTION as the compare function.
COMPARE-FUNCTION is a function which takes two arguments, A and B, and
returns non-nil if A is less than B, and nil otherwise."
(cons 'BINTREE
(cons (elib-node-create nil nil nil)
compare-function)))
(defun bintree-p (obj)
"return t if OBJ is a binary tree, nil otherwise."
(eq (car-safe obj) 'BINTREE))
(defun bintree-compare-function (tree)
"Return the comparision function for the binary tree TREE."
(elib-bintree-cmpfun tree))
(defun bintree-empty (tree)
"Return t if the binary tree TREE is empty, otherwise return nil."
(null (elib-bintree-root tree)))
(defun bintree-enter (tree data)
"In the binary tree TREE, insert DATA."
(let ((cmpfun (elib-bintree-cmpfun tree))
(node (elib-bintree-dummyroot tree))
(new-node (elib-node-create nil nil data)))
(if (null (elib-node-left node))
(elib-node-set-left node new-node)
(setq node (elib-node-left node))
(while node
(cond
((funcall cmpfun data (elib-node-data node))
(if (elib-node-left node)
(setq node (elib-node-left node))
(elib-node-set-left node new-node)
(setq node nil)))
((funcall cmpfun (elib-node-data node) data)
(if (elib-node-right node)
(setq node (elib-node-right node))
(elib-node-set-right node new-node)
(setq node nil)))
(t
(elib-node-set-data node data)
(setq node nil)))))))
(defun bintree-delete (tree data)
"From the binary tree TREE, delete DATA.
Return the element in TREE which matched DATA, or nil if no element matched."
(let* ((cmpfun (elib-bintree-cmpfun tree))
(upper-node (elib-bintree-dummyroot tree)) ; Start with the dummy node
(branch 0) ; Left branch
(branch-node (elib-node-left upper-node))
node-data
right-node) ; Only used while deleting,
; not while searching
(if (null branch-node)
nil
(while upper-node
(setq node-data (elib-node-data branch-node))
(cond
((funcall cmpfun data node-data) ; data<node-data => go left
(setq upper-node branch-node
branch-node (elib-node-left upper-node)
branch 0))
((funcall cmpfun node-data data) ; data>node-data => go right
(setq upper-node branch-node
branch-node (elib-node-right upper-node)
branch 1))
(t ; This is the node we want
; to delete.
(cond
((null (elib-node-left branch-node)) ; Empty left node?
(elib-node-set-branch upper-node branch
(elib-node-right branch-node)))
((null (elib-node-right branch-node)) ; Empty right node?
(elib-node-set-branch upper-node branch
(elib-node-left branch-node)))
(t ; Both branches occupied.
;; At this point `branch-node' points at the node we want
;; to delete. Both the right and the left branches are
;; non-nil, so we will take the data of the rightmost node
;; of the left subtree and put into `branch-node'.
(setq right-node branch-node
branch 0)
(while (elib-node-right (elib-node-branch right-node branch))
(setq right-node (elib-node-branch right-node branch)
branch 1))
(elib-node-set-data branch-node
(elib-node-data (elib-node-branch right-node
branch)))
(elib-node-set-branch right-node branch
(elib-node-left
(elib-node-branch right-node branch)))))
(setq upper-node nil)))))))
(defun bintree-member (tree data)
"Return the element in the binary tree TREE which matches DATA.
Matching uses the compare function previously specified in `bintree-create'
when TREE was created.
If there is no such element in the tree, the value is nil."
(let ((node (elib-bintree-root tree))
(compare-function (elib-bintree-cmpfun tree))
found)
(while (and node
(not found))
(cond
((funcall compare-function data (elib-node-data node))
(setq node (elib-node-left node)))
((funcall compare-function (elib-node-data node) data)
(setq node (elib-node-right node)))
(t
(setq found t))))
(if node
(elib-node-data node)
nil)))
(defun bintree-map (__map-function__ tree)
"Apply MAP-FUNCTION to all elements in the binary tree TREE."
(elib-bintree-mapc
(function (lambda (node)
(elib-node-set-data node
(funcall __map-function__
(elib-node-data node)))))
(elib-bintree-root tree)))
(defun bintree-first (tree)
"Return the first element in the binary tree TREE, or nil if TREE is empty."
(let ((node (elib-bintree-root tree)))
(if node
(progn
(while (elib-node-left node)
(setq node (elib-node-left node)))
(elib-node-data node))
nil)))
(defun bintree-last (tree)
"Return the last element in the binary tree TREE, or nil if TREE is empty."
(let ((node (elib-bintree-root tree)))
(if node
(progn
(while (elib-node-right node)
(setq node (elib-node-right node)))
(elib-node-data node))
nil)))
(defun bintree-copy (tree)
"Return a copy of the binary tree TREE.
Note: This function is recursive and might result in an
`max eval depth exceeded' error."
(let ((new-tree (bintree-create
(elib-bintree-cmpfun tree))))
(elib-node-set-left (elib-bintree-dummyroot new-tree)
(elib-bintree-do-copy (elib-bintree-root tree)))
new-tree))
;;
;; Not the fastest way to do this.
;;
(defun bintree-flatten (tree)
"Return a sorted list containing all elements of the binary tree TREE."
(nreverse
(let ((treelist nil))
(elib-bintree-mapc (function (lambda (node)
(setq treelist (cons (elib-node-data node)
treelist))))
(elib-bintree-root tree))
treelist)))
;;
;; Not the fastest way to do this:
;;
(defun bintree-size (tree)
"Return the number of elements in the binary tree TREE."
(let ((treesize 0))
(elib-bintree-mapc (function (lambda (data)
(setq treesize (1+ treesize))))
(elib-bintree-root tree))
treesize))
(defun bintree-clear (tree)
"Clear the binary tree TREE."
(elib-node-set-left (elib-bintree-dummyroot tree) nil))